import java.util.ArrayList;
import java.util.Collections;

/**
 * This class holds and manages Game objects, this is our game driver
 * 
 * @author michal
 * 
 */
/**
 * @author michal
 * 
 */
public class Game {

  ArrayList<Player> players;
  EconomyBoard      ecoBoard;
  EconomyCard       currentEconomy;
  Player            currentPlayer;
  int               xDie;               // storing die roll
  int               yDie;               // storing die roll
  int               diceDifferenceTrack;
  int               greenDie;
  // int hitCount;
  int               turn;
  int               gameNrOfOilWells;
  int               oilHit;
  boolean           domestic;
  boolean           foreign;
  boolean           oilNews_22;         // lingering news effects
  boolean           longColdWinter_55;
  boolean           middleEast_44;
  boolean           declaredVictory;
  boolean           checkedHits;
  int               declaringPlayer;
  int               finalRoundCounter;

  /**
   * default constructor for objects of class Game, it sets game to beggining of
   * the game state.
   * 
   */
  public Game() {
    this.players = new ArrayList<Player>();
    this.ecoBoard = new EconomyBoard();
    this.currentEconomy = new EconomyCard();
    this.domestic = false;
    this.foreign = false;
    this.gameNrOfOilWells = 0;
    this.diceDifferenceTrack = 0;
    this.oilHit = 0;
    this.oilNews_22 = false;
    this.longColdWinter_55 = false;
  }

  /**
   * listPlayers() method lists all the players currently loaded in game
   * 
   * @author michal
   */
  public void listPlayers() {
    StdOut.println("Players: ");
    for (Player p : players) { // lists players
      StdOut.println(players.indexOf(p) + ":" + p);
    }
  }

  /**
   * addPlayer() method adds player. Maximum of 4 players per game
   * 
   * @author michal
   */
  public void addPlayer() {
    listPlayers();

    if (players.size() < 4) {
      StdOut.println("Please enter name of the player");
      String playerName = StdIn.readString();
      int playerNumber = players.size() + 1;
      int cash = 200;
      if (playerName.contains("Mick")) {
        cash = 3000;
      }
      int crudeOilBarrels = 2;
      int gassolineBarrels = 2;
      Player p = new Player(playerNumber, cash, playerName, crudeOilBarrels,
          gassolineBarrels);
      p.playerBoard.clearBoard();
      players.add(p);
    } else {
      StdOut.println("No more than 4 players");
    }
  }

  /**
   * newTurn() method keeps track of the currentPlayer
   * 
   */
  public void nextPlayer() {
    if (currentPlayer.playerNumber < players.size()) {
      Player tempPlayer = players.get(currentPlayer.playerNumber);
      currentPlayer = tempPlayer;
    } else {
      currentPlayer = players.get(0);
    }
    this.domestic = false;
    this.foreign = false;
    this.checkedHits = false;
    currentPlayer.rolled = false;
    this.turn++;
    if (declaredVictory) {
      finalRoundCounter++;
    }

  }

  public void specialRound() {
    // redundant
  }

  /**
   * buyAsset() Method allows to buy assets by the player. Updates his gameBoard
   * and updates his cash by correct value according to current economy.
   * 
   * @author michal
   * 
   * @param type
   *          Type of the building
   * @param xRef
   *          Horizontal reference o the grid
   * @param yRef
   *          Vertical reference o the grid
   */
  public void buyAsset(String type, int xRef, int yRef) {
    if (type.contentEquals("drillingRig")) {
      currentPlayer.cash -= currentEconomy.drillingRigBuy;
      currentPlayer.nrOfDrillingRigs++;
      currentPlayer.playerBoard.buyDrillingRig(xRef, yRef);
    } else if (type.contains("gasStation")) {
      currentPlayer.cash -= currentEconomy.gasStationBuy;
      currentPlayer.nrOfGasStations++;
      currentPlayer.playerBoard.buyGasStation(xRef, yRef);
    } else if (type.contains("refinery")) {
      currentPlayer.cash -= currentEconomy.refineryBuy;
      currentPlayer.nrOfRefineries++;
      currentPlayer.playerBoard.buyRefinery(xRef, yRef);
    } else if (type.contains("oilWell")) {
      currentPlayer.cash -= (gameNrOfOilWells * 5) + 5;
      currentPlayer.nrOfOilWells++;
      gameNrOfOilWells++;
      currentPlayer.playerBoard.buyOilWell(xRef, yRef);
    }
  }

  /**
   * sellAsset() Method allows to sell assets by the player. Updates his
   * gameBoard and updates his cash by correct value according to current
   * economy.
   * 
   * @author michal
   * @param type
   * @param xRef
   * @param yRef
   * 
   */
  public void sellAsset(String type, int xRef, int yRef) {
    if (type.contentEquals("drillingRig")) {
      currentPlayer.cash += currentEconomy.drillingRigBuy;
      currentPlayer.nrOfDrillingRigs--;
      currentPlayer.playerBoard.sellBuilding(xRef, yRef);
    } else if (type.contains("gasStation")) {
      currentPlayer.cash += currentEconomy.gasStationBuy;
      currentPlayer.nrOfGasStations--;
      currentPlayer.playerBoard.sellBuilding(xRef, yRef);
    } else if (type.contains("refinery")) {
      currentPlayer.cash += currentEconomy.refineryBuy;
      currentPlayer.nrOfRefineries--;
      currentPlayer.playerBoard.sellBuilding(xRef, yRef);
    } else if (type.contains("oilWell")) {
      currentPlayer.cash += (gameNrOfOilWells * 5) + 5;
      currentPlayer.nrOfOilWells--;
      gameNrOfOilWells--;
      currentPlayer.playerBoard.sellBuilding(xRef, yRef);
    }
  }

  /**
   * diceRoll() Rolls all dice if there is overRoll of dice track on ecoBoard it
   * calls method to change economy depending on green die roll.
   * 
   * @author michal
   */
  public void diceRoll() {
    currentPlayer.rolled = true;
    xDie = StdRandom.uniform(1, 7);
    yDie = StdRandom.uniform(1, 7);
    greenDie = StdRandom.uniform(1, 7);
    int currentDiceDifference = ecoBoard.diceDifferenceTrack;

    int diceDifference = Math.abs(xDie - yDie);
    currentDiceDifference = (currentDiceDifference + diceDifference) % 9;
    StdOut.println("***DEV MODE***");
    StdOut.println("dice difference: " + diceDifference);
    StdOut.println("ecoBoard dieTrack: " + ecoBoard.diceDifferenceTrack);
    StdOut.println("current difference: " + currentDiceDifference);

    if (currentDiceDifference < ecoBoard.diceDifferenceTrack
        || currentDiceDifference == 8) {
      ecoBoard.diceDifferenceTrack = currentDiceDifference;
      StdOut.println("economy change");
      changeEconomy(greenDie);
    } else {
      ecoBoard.diceDifferenceTrack = currentDiceDifference;
    }
    currentDiceDifference = 0;

    // news
    if (xDie == 2 && yDie == 2 && oilNews_22) {
      oilNews_22 = false;
    } else if (xDie == yDie && longColdWinter_55) {
      ecoBoard.buyGasDomestic += 5;
      ecoBoard.sellGasDomestic += 5;

    } else if (xDie == 5 && yDie == 5 && longColdWinter_55) {
      longColdWinter_55 = false;
    } else if (xDie == 4 && yDie == 4 && middleEast_44) {
      middleEast_44 = false;
    }

  }

  /**
   * changeEconomy(int greenDie) changes current economy (prices of assets and
   * customer market)according to game rules
   * 
   * @author michal
   * @param greenDie
   *          an random int [1,6] initiated in diceRoll()
   */
  public void changeEconomy(int greenDie) {
    int i = greenDie;
    String str = currentEconomy.economy;

    if (str.contains("Depression")) {
      if (i == 1 || i == 2 || i == 3 || i == 4) {
        currentEconomy.recovery();
      } else {
        currentEconomy.expansion();
      }
    }//
    else if (str.contains("Downturn")) {
      if (i == 1) {
        currentEconomy.prosperity();
      } else if (i == 2 || i == 3 || i == 4 || i == 5) {
        currentEconomy.recession();
      } else {
        currentEconomy.depression();
      }
    }//
    else if (str.contains("Expansion")) {
      if (i == 1) {
        currentEconomy.recovery();
      } else if (i == 2 || i == 3 || i == 4 || i == 5) {
        currentEconomy.rapidGrowth();
      } else {
        currentEconomy.prosperity();
      }
    }//
    else if (str.contains("Prosperity")) {
      if (i == 1) {
        currentEconomy.rapidGrowth();
      } else if (i == 2 || i == 3 || i == 4 || i == 5) {
        currentEconomy.downturn();
      } else {
        currentEconomy.recession();
      }

    }//
    else if (str.contains("Rapid Growth")) {
      if (i == 1) {
        currentEconomy.expansion();
      } else if (i == 2 || i == 3 || i == 4 || i == 5) {
        currentEconomy.prosperity();
      } else {
        currentEconomy.downturn();
      }

    }//
    else if (str.contains("Recession")) {
      if (i == 1 || i == 2 || i == 3) {
        currentEconomy.depression();
      } else {
        currentEconomy.recovery();
      }

    }//
    else if (str.contains("Recovery")) {
      if (i == 1) {
        currentEconomy.downturn();
      } else if (i == 2 || i == 3 || i == 4 || i == 5) {
        currentEconomy.expansion();
      } else {
        currentEconomy.rapidGrowth();
      }

    }

  }

  public void checkHits() {

    String[][] playerBoard = currentPlayer.playerBoard.asets;
    int x = xDie - 1;
    int y = yDie - 1;
    String str;
    int doubleCheck = 0;
    for (int i = 0; i < 6; i++) {
      if (playerBoard[x][i].contains("|Refin|")) {
        StdOut.println("Hit refinery.");
        if (currentPlayer.crudeOilBarrels > 0) {
          StdOut.println("Do you want to convert one Crude Oil to Gassoline?");
          StdOut.println(" y/n ?");
          str = StdIn.readLine();
          if (str.equals("y")) {
            currentPlayer.crudeOilBarrels--;
            currentPlayer.gassolineBarrels++;
            StdOut.println("Success.");
          } else {
            StdOut.println("No Crude Oil to convert");
          }
        }
        checkedHits = true;
      }//
      else if (playerBoard[x][i].contains("|D_Rig|")) {
        oilHit++;
        doubleCheck = i;
        for (int j = 0; j < 6; j++) {
          if (playerBoard[j][y].contains("|D_Rig|")) {
            if (doubleCheck == y) {
              StdOut.println("Double hit on drilling rig ");
              StdOut.println("Do you want to convert it into Oil Well? ");
              StdOut.println("Cost: " + (gameNrOfOilWells * 5) + 5);
              StdOut.println(" y/n ?");
              str = StdIn.readLine();
              if (str.equals("y")) {
                buyAsset("oilWell", x, y);
                currentPlayer.playerBoard.asets = playerBoard;
                currentPlayer.playerBoard.printBoard();
              }
            }
          }
        }
      }//
      else if (playerBoard[x][i].contains("|OilWe|")) {
        StdOut.println("Hit Oil Well ");
        StdOut.println("Crude Oil +2 ");
        currentPlayer.crudeOilBarrels += 2;
        if (oilNews_22) {
          currentPlayer.cash += 10;
        }

      }//
      else if (playerBoard[x][i].contains("|GasSt|")) {
        StdOut.println("Hit on Gas Station ");
        if (currentPlayer.gassolineBarrels > 0) {
          StdOut.println("Sell one gasoline on consumer market? ");
          StdOut.println("Current Price: " + ecoBoard.consumerMarket);
          StdOut.println(" y/n ?");
          str = StdIn.readLine();
          if (str.equals("y")) {
            ecoBoard.consumerMarket--;// we sell one below the current price
            currentPlayer.cash += ecoBoard.consumerMarket;
            currentPlayer.gassolineBarrels--;
          }
        } else {
          StdOut.println("You`ve got no gasoline to sell.");
        }
      }
    }// next for loop vvv
    for (int j = 0; j < 6; j++) {
      if (playerBoard[j][y].contains("|Refin|")) {
        StdOut.println("Hit refinery.");
        if (currentPlayer.crudeOilBarrels > 0) {
          StdOut.println("Do you want to convert one Crude Oil to Gassoline?");
          StdOut.println(" y/n ?");
          str = StdIn.readLine();
          if (str.equals("y")) {
            currentPlayer.crudeOilBarrels--;
            currentPlayer.gassolineBarrels++;
            StdOut.println("Success.");
          } else {
            StdOut.println("No Crude Oil to convert");
          }
        }
      }//

      else if (playerBoard[j][y].contains("|OilWe|")) {
        StdOut.println("Hit Oil Well ");
        StdOut.println("Crude Oil +2 ");
        currentPlayer.crudeOilBarrels += 2;
      }//
      else if (playerBoard[j][y].contains("|GasSt|")) {
        StdOut.println("Hit on Gas Station ");
        if (currentPlayer.gassolineBarrels > 0) {
          StdOut.println("Sell one gasoline on consumer market? ");
          StdOut.println("Current Price: " + ecoBoard.consumerMarket);
          StdOut.println(" y/n ?");
          str = StdIn.readLine();
          if (str.equals("y")) {
            ecoBoard.consumerMarket--;// we sell one below the current price
            currentPlayer.cash += ecoBoard.consumerMarket;
            currentPlayer.gassolineBarrels--;
          }
        } else {
          StdOut.println("You`ve got no gasoline to sell.");
        }
      }
    }
    if (oilHit > 0) {
      StdOut.println("single hits drilling rig ");
    }
    checkedHits = true;

  }

  /**
   * @author Ryan buyOilForeign() method allows to buy oil on the foreign
   *         market, checks if current price on the market is not maximum.
   */
  public void buyOilForeign() {
    if (ecoBoard.buyOilForeign <= EconomyBoard.maxOilPrice) {
      currentPlayer.cash -= ecoBoard.buyOilForeign;
      ecoBoard.buyOilForeign += EconomyBoard.oilIncrement;
      ecoBoard.sellOilForeign += EconomyBoard.oilIncrement;
      StdOut.println("Success, your current cash: " + currentPlayer.cash);
    } else {
      StdOut.println("No more oil on foreign market");
    }
  }

  /**
   * @author Ryan sellOilForeign() method allows to sell oil on the foreign
   *         market, checks if current price on the market is not maximum.
   */
  public void sellOilForeign() {
    if (ecoBoard.buyOilForeign <= EconomyBoard.maxOilPrice) {
      currentPlayer.cash -= ecoBoard.buyOilForeign;
      ecoBoard.buyOilForeign += EconomyBoard.oilIncrement;
      StdOut.println("Success, your current cash: " + currentPlayer.cash);
    } else {
      StdOut.println("No more oil on foreign market");
    }

  }

  /**
   * @author Ryan buyGasolineForeign() method allows to buy gasoline on the
   *         foreign market, checks if current price on the market is not
   *         maximum.
   */
  public void buyGasolineForeign() {
    if (ecoBoard.buyGasForeign <= EconomyBoard.maxGasPrice) {
      currentPlayer.cash -= ecoBoard.buyGasForeign;
      ecoBoard.buyGasForeign += EconomyBoard.gasIncrement;
      ecoBoard.sellGasForeign += EconomyBoard.gasIncrement;
      StdOut.println("Success, your current cash: " + currentPlayer.cash);
    } else {
      StdOut.println("No more oil on foreign market");
    }
  }

  /**
   * @author Ryan sellGasolineForeign() method allows to sell gasoline on the
   *         foreign market, checks if current price on the market is not
   *         maximum.
   */
  public void sellGasolineForeign() {
    if (ecoBoard.buyGasForeign <= EconomyBoard.maxGasPrice) {
      currentPlayer.cash -= ecoBoard.buyGasForeign;
      ecoBoard.buyGasForeign += EconomyBoard.gasIncrement;
      StdOut.println("Success, your current cash: " + currentPlayer.cash);
    } else {
      StdOut.println("No more Gasoline on foreign market");
    }
  }

  /**
   * @author Ryan buyOilDomestic() method allows to buy oil on the domestic
   *         market, checks if current price on the market is not maximum.
   */
  public void buyOilDomestic() {
    if (ecoBoard.buyOilDomestic <= EconomyBoard.maxOilPrice) {
      currentPlayer.cash -= ecoBoard.buyOilDomestic;
      ecoBoard.buyOilDomestic += EconomyBoard.oilIncrement;
      ecoBoard.sellOilDomestic += EconomyBoard.oilIncrement;
      StdOut.println("Success, your current cash: " + currentPlayer.cash);
    } else {
      StdOut.println("No more oil on domestic market");
    }
  }

  /**
   * @author Ryan sellOilDomestic() method allows to sell oil on the domestic
   *         market, checks if current price on the market is not maximum.
   */
  public void sellOilDomestic() {
    if (ecoBoard.buyOilDomestic <= EconomyBoard.maxOilPrice) {
      currentPlayer.cash -= ecoBoard.buyOilForeign;
      ecoBoard.buyOilDomestic += EconomyBoard.oilIncrement;
      StdOut.println("Success, your current cash: " + currentPlayer.cash);
    } else {
      StdOut.println("No more Gasoline on foreign market");
    }
  }

  /**
   * @author Ryan buyGasolineDomestic() method allows to buy gasoline on the
   *         domestic market, checks if current price on the market is not
   *         maximum.
   */
  public void buyGasolineDomestic() {
    if (ecoBoard.buyGasDomestic <= EconomyBoard.maxGasPrice) {
      currentPlayer.cash -= ecoBoard.buyGasDomestic;
      ecoBoard.buyGasDomestic += EconomyBoard.gasIncrement;
      ecoBoard.sellGasDomestic += EconomyBoard.gasIncrement;
      StdOut.println("Success, your current cash: " + currentPlayer.cash);
    } else {
      StdOut.println("No more oil on domestic market");
    }
  }

  /**
   * @author Ryan sellOilDomestic() method allows to sell gasoline on the
   *         domestic market, checks if current price on the market is not
   *         maximum.
   */
  public void sellGasolineDomestic() {
    if (ecoBoard.buyGasDomestic <= EconomyBoard.maxGasPrice) {
      currentPlayer.cash -= ecoBoard.buyGasDomestic;
      ecoBoard.buyGasDomestic += EconomyBoard.gasIncrement;
      StdOut.println("Success, your current cash: " + currentPlayer.cash);
    } else {
      StdOut.println("No more Gasoline on foreign market");
    }

  }

  // @formatter:off
  public String newsCall(int xDie, int yDie) {
    String news = "No major news";
    if   (((xDie == 1) && (yDie == 1))
      || (((xDie == 3) && (yDie == 3) 
      ||   (xDie == 6) && (yDie == 6)))) {
      int newsCall = StdRandom.uniform(1, 9); // [1,9)
      if (newsCall == 1) {
        for (Player p : players) {
          p.cash -= p.nrOfDrillingRigs * 2;
          p.cash -= p.nrOfOilWells * 5;
          p.cash -= p.nrOfGasStations * 15;
          p.nrOfRefineries -= p.nrOfRefineries * 20;
          news = "Aggressive National debt reduction taxes";
        }

      } else if (newsCall == 2) {
        news = "Congress actively encourages arctic oil development";
        oilNews_22 = true;

      } else if (newsCall == 3) {
        news = "Global warming threat";
        for (Player p : players) {
          p.cash -= p.nrOfRefineries * 25;
        }

      } else if (newsCall == 4) {
        news = "Long cold winter forecast";
        ecoBoard.buyGasDomestic += 5;
        ecoBoard.sellGasDomestic += 5;

      } else if (newsCall == 5) {
        news = "Middle east engulfed in civil wars";

      } else if (newsCall == 6) {
        news = "Snap inspection at the huge oil tank" + "\n"
            + " farm finds numerous safety violations";
        for (Player p : players) {
          p.cash -= p.crudeOilBarrels * 3;
          p.cash -= p.gassolineBarrels * 5;
        }

      } else if (newsCall == 7) {
        news = "State sales taxes due soon";
        for (Player p : players) {
          p.cash -= p.nrOfGasStations * 5;
        }

      } else if (newsCall == 8) {
        news = "Uncertainty in the word markets" + "\n"
            + " high U.S strategic petroleum reserve";
        ecoBoard.buyOilForeign -= 5;
        ecoBoard.sellOilForeign -= 5;
        ecoBoard.buyOilDomestic += 5;
        ecoBoard.sellOilDomestic += 5;
        ecoBoard.consumerMarket -= 5;
      }
    }
    return news;
  }
  // @formatter:on

  public void endGame() {
    currentEconomy.depression();
    EconomyCard e = currentEconomy;
    for (Player p : players) {
      p.cash += p.nrOfDrillingRigs * e.drillingRigSell;
      p.nrOfDrillingRigs = 0;
      p.cash += p.nrOfGasStations * e.gasStationSell;
      p.nrOfGasStations = 0;
      p.cash += p.nrOfOilWells * e.oilWellSell;
      gameNrOfOilWells -= p.nrOfOilWells;
      p.nrOfOilWells = 0;
      p.cash += p.nrOfRefineries * e.refinerySell;
      p.nrOfRefineries = 0;
    }
    for (int i = players.size() - 1; i > 0; i--) {
      for (int j = 0; j < i; j++) {
        if (players.get(j).cash < players.get(j + 1).cash) {
          Collections.swap(players, j, j + 1);
        }
      }
    }
    for (int i = 0; i < players.size(); i++) {
      if (i == 0) {
        StdOut.println("The winner is: ");
      } else if (i == 1) {
        StdOut.println("Second place: ");
      } else if (i == 2) {
        StdOut.println("Third place: ");
      }
      StdOut.println("--------------------------");
      StdOut.println("Player: " + players.get(i).playerName);
      StdOut.println("Cash: " + players.get(i).cash);
    }
    System.exit(0);
  }
}
